package com.cchc.k8s.kernel;

import com.cchc.k8s.request.CreateDeploymentRequest;
import io.kubernetes.client.custom.Quantity;
import io.kubernetes.client.openapi.models.*;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * file：DeploymentBuilder.java
 * description:
 * date: 2021-09-18 17:51
 * author: wenrui
 * version: 1.0
 */
@Component
public class DeploymentBuilder {

    @Value("${harbor.host}")
    String harborHost;
    @Value("${harbor.repository}")
    String harborRepository;

    /**
     * 构建Deployment
     *
     * @param request 创建Deployment请求
     * @return V1Deployment
     */
    public V1Deployment build(CreateDeploymentRequest request) {
        V1Deployment deployment = new V1Deployment();

        Map<String, String> labelsMap = new HashMap<>(1);
        labelsMap.put("app", request.getAppName());

        //  元数据 metadata
        V1ObjectMeta meta = new V1ObjectMeta();
        meta.name(request.getAppName() + "-dm");
        meta.labels(labelsMap);

        V1DeploymentSpec v1DeploymentSpec = new V1DeploymentSpec();
        // 标签选择器 selector
        V1LabelSelector selector = new V1LabelSelector();
        selector.matchLabels(labelsMap);

        // pod相关信息
        V1PodTemplateSpec templateSpec = new V1PodTemplateSpec();
        V1PodSpec podSpec = new V1PodSpec();
        // 容器 container
        V1Container container = new V1Container();
        // 镜像地址，从私有仓库拉取
        container.image(harborHost + "/" + harborRepository + "/" + request.getAppName() + ":" + request.getAppVersion());
        container.name(request.getAppName());
        // port
        V1ContainerPort containerPort = new V1ContainerPort();
        containerPort.containerPort(request.getAppPort()).name("http");
        List<V1ContainerPort> containerPorts = new ArrayList<>();
        containerPorts.add(containerPort);
        container.ports(containerPorts);
        // env 环境变量
        if (CollectionUtils.isNotEmpty(request.getEnvList())) {
            for (Map<String, String> envMap : request.getEnvList()) {
                for (Map.Entry<String, String> entry : envMap.entrySet()) {
                    V1EnvVar envVar = new V1EnvVar();
                    envVar.name(entry.getKey()).value(entry.getValue());
                    container.addEnvItem(envVar);
                }
            }
        }
        // 容器运行所需内存，cpu大小
        if (request.getResourceRequest() != null) {
            V1ResourceRequirements resourceRequirements = new V1ResourceRequirements();
            CreateDeploymentRequest.ResourceRequest resourceRequest = request.getResourceRequest();
            // 需求限制
            Map<String, Quantity> requestMap = new HashMap<>(2);
            requestMap.put("memory", new Quantity(resourceRequest.getMemoryRequest()));
            requestMap.put("cpu", new Quantity(resourceRequest.getCpuRequest()));
            resourceRequirements.requests(requestMap);
            // 最大限制
            Map<String, Quantity> limitMap = new HashMap<>(2);
            limitMap.put("memory", new Quantity(resourceRequest.getMemoryLimit()));
            limitMap.put("cpu", new Quantity(resourceRequest.getCpuLimit()));
            resourceRequirements.limits(limitMap);
            container.resources(resourceRequirements);
        }
        List<V1Container> containers = new ArrayList<>();
        containers.add(container);
        podSpec.containers(containers);
        // secret
        V1LocalObjectReference v1LocalObjectReference = new V1LocalObjectReference();
        v1LocalObjectReference.name("harbor-secret");
        List<V1LocalObjectReference> list = new ArrayList<>();
        list.add(v1LocalObjectReference);
        podSpec.imagePullSecrets(list);

        templateSpec.spec(podSpec)
                .metadata(meta);

        // 滚动升级策略 strategy
//        V1DeploymentStrategy strategy = new V1DeploymentStrategy();
//        strategy.type("RollingUpdate");
//        V1RollingUpdateDeployment rollingUpdateDeployment = new V1RollingUpdateDeployment();
//        IntOrString intOrString = new IntOrString("25%");
//        rollingUpdateDeployment.maxSurge(intOrString)
//                .maxUnavailable(intOrString);
//        strategy.rollingUpdate(rollingUpdateDeployment);

        v1DeploymentSpec.replicas(request.getAppReplicas())
                .selector(selector)
                .template(templateSpec);
//                .strategy(null);

        deployment.apiVersion("apps/v1")
                .kind("Deployment")
                .metadata(meta)
                .setSpec(v1DeploymentSpec);

        return deployment;
    }
}
